package com.jeomo.common.core.util;

import com.jeomo.common.core.dto.ITree;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * <h3>树形工具</h3>
 * <p></p>
 *
 * @author : qibotian
 * @date : 2020-09-28 10:35
 **/
public class TreeUtil {

    /**
     * 构建树
     * @param nodes 树节点
     * @return
     * @throws NoSuchFieldException
     * @throws IllegalAccessException
     */
    public static List<ITree> buildTree(List<ITree> nodes)
            throws NoSuchFieldException, IllegalAccessException, InstantiationException {
        //首先尋找出所有沒有父节点 或者 找不到父节点的节点
        List<ITree> parentNodes = new ArrayList<>();
        for(ITree node : nodes){
            if(findParentNode(node, nodes) == null) {
                parentNodes.add(node);
            }
        }
        for(ITree node : parentNodes) {
            buildChildren(node, nodes);
        }
        return parentNodes;
    }

    private static ITree findParentNode(ITree node, List<ITree> allNode) throws NoSuchFieldException, IllegalAccessException {
        String parentCode = (String) ClassUtil.getFiledValue(node, node.getParentFieldName());
        if(StringUtils.isEmpty(parentCode)) {
            return null;
        }
        for(ITree n : allNode){
            if(parentCode.equals(ClassUtil.getFiledValue(n, n.getCodeFieldName()))) {
                return n;
            }
        }
        return null;
    }

    /**
     * 构建树
     * @param nodes 树节点
     * @param rootNodeCode 树的根节点值
     * @return
     * @throws NoSuchFieldException
     * @throws IllegalAccessException
     */
    public static List<ITree> buildTree(List<ITree> nodes, String rootNodeCode)
            throws NoSuchFieldException, IllegalAccessException, InstantiationException {
      return buildTree(nodes, rootNodeCode, false, null, null);
    }

    /**
     * 构建树
     * @param nodes 树节点
     * @param rootNodeCode 树的根节点值
     * @return
     * @throws NoSuchFieldException
     * @throws IllegalAccessException
     */
    public static List<ITree> buildTree(List<ITree> nodes, String rootNodeCode, boolean containCurrentNode)
            throws NoSuchFieldException, IllegalAccessException, InstantiationException {
        return buildTree(nodes, rootNodeCode, false, null, null, containCurrentNode);
    }

    /**
     * 构建树
     * @param nodes 树节点
     * @param rootNodeCode 树的根节点值
     * @return
     * @throws NoSuchFieldException
     * @throws IllegalAccessException
     */
    public static List<ITree> buildTreeWithDefaultGroup(List<ITree> nodes, String rootNodeCode, Class<?> treeNodeClass)
            throws NoSuchFieldException, IllegalAccessException, InstantiationException {
        return buildTree(nodes, rootNodeCode, true, treeNodeClass, buildDefaultGroup(treeNodeClass));
    }

    public static List<ITree> buildTreeWithDefaultGroup(List<ITree> nodes, String rootNodeCode, Class<?> treeNodeClass, String defaultGroupCode)
            throws NoSuchFieldException, IllegalAccessException, InstantiationException {
        return buildTree(nodes, rootNodeCode, true, treeNodeClass, buildDefaultGroup(treeNodeClass, defaultGroupCode, null));
    }

    public static List<ITree> buildTreeWithDefaultGroup(List<ITree> nodes, String rootNodeCode, Class<?> treeNodeClass, String defaultGroupCode, String defaultGroupName)
            throws NoSuchFieldException, IllegalAccessException, InstantiationException {
        return buildTree(nodes, rootNodeCode, true, treeNodeClass, buildDefaultGroup(treeNodeClass, defaultGroupCode, defaultGroupName));
    }

    public static List<ITree> buildTree(List<ITree> nodes, String rootNodeCode, boolean needDefaultGroup, Class<?> treeNodeClass, ITree defaultGroup)
            throws NoSuchFieldException, IllegalAccessException, InstantiationException {
        return buildTree(nodes, rootNodeCode, true, treeNodeClass, defaultGroup, false);
    }
    /**
     * @param nodes 树的所有节点
     * @param rootNodeCode 树的根节点值
     * @param needDefaultGroup 是否需要包装默认分组，即所有的非分组节点，且上级节点在nodes里找不到的情况下，会默认放到默认分组里
     * @param treeNodeClass 树节点类型
     * @return
     * @throws NoSuchFieldException
     * @throws IllegalAccessException
     */
    public static List<ITree> buildTree(List<ITree> nodes, String rootNodeCode, boolean needDefaultGroup, Class<?> treeNodeClass, ITree defaultGroup, boolean containCurrentNode)
            throws NoSuchFieldException, IllegalAccessException, InstantiationException {
        List<ITree> trees = new ArrayList<>();
        if(needDefaultGroup) {
            //确保默认分组放在第一位
            trees.add(defaultGroup);
        }
        ITree currentNode = null;
        for (ITree node : nodes) {
            if(rootNodeCode.equals(ClassUtil.getFiledValue(node, node.getCodeFieldName()))) {
                currentNode = node;
            }
        }
        if(containCurrentNode) {
            trees.add(buildChildren(currentNode, nodes));
        } else {
            for (ITree node : nodes) {
                Object parentCode = ClassUtil.getFiledValue(node, node.getParentFieldName());
                if(rootNodeCode.equals(parentCode)) {
                    trees.add(buildChildren(node, nodes));
                }
            }
        }
        if(needDefaultGroup) {
            List<ITree> defaultGroupChildren = new ArrayList<>();
            Iterator<ITree> iter = trees.iterator();
            while (iter.hasNext()) {
                ITree tree = iter.next();
                if(!tree.isGroup()) {
                    defaultGroupChildren.add(tree);
                    iter.remove();
                }
            }
            ClassUtil.setFiledValue(defaultGroup, defaultGroup.getChildrenFieldName(), defaultGroupChildren);
        }
        return trees;
    }

    private static ITree buildChildren(ITree tree, List<ITree> nodes) throws NoSuchFieldException, IllegalAccessException {
        //创建自己子节点
        List<ITree> children = null;
        Object treeCode = ClassUtil.getFiledValue(tree, tree.getCodeFieldName());
        for(ITree node : nodes) {
            if(treeCode.equals(ClassUtil.getFiledValue(node, node.getParentFieldName()))) {
                if(children == null) {
                    children = initChildren(tree);
                }
                children.add(buildChildren(node, nodes));
            }
        }
        return tree;
    }

    /**
     * 初始化子节点
     */
    private static List<ITree> initChildren(ITree tree) throws NoSuchFieldException, IllegalAccessException {
        String childrenFieldName = tree.getChildrenFieldName();
        Class<? extends ITree> clazz = tree.getClass();
        Field childrenField = clazz.getDeclaredField(childrenFieldName);
        childrenField.setAccessible(true);
        ArrayList<ITree> children = new ArrayList<ITree>();
        childrenField.set(tree, children);
        return children;
    }

    /**
     * 新增子节点
     */
    private static void insertChildren(ITree tree) throws NoSuchFieldException, IllegalAccessException {
        String childrenFieldName = tree.getChildrenFieldName();
        Class<? extends ITree> clazz = tree.getClass();
        Field childrenField = clazz.getField(childrenFieldName);
        childrenField.setAccessible(true);
        childrenField.set(tree, new ArrayList());
    }

    /**
     * 创建默认节点
     * @param treeNodeClass
     * @return
     * @throws IllegalAccessException
     * @throws InstantiationException
     * @throws NoSuchFieldException
     */
    private static ITree buildDefaultGroup(Class<?> treeNodeClass)
            throws IllegalAccessException, InstantiationException, NoSuchFieldException {
        return buildDefaultGroup(treeNodeClass, null, null);
    }

    /**
     * 创建默认节点
     * @param treeNodeClass
     * @param defaultGroupCode
     * @param defaultGroupName
     * @return
     * @throws IllegalAccessException
     * @throws InstantiationException
     * @throws NoSuchFieldException
     */
    private static ITree buildDefaultGroup(Class<?> treeNodeClass, String defaultGroupCode, String defaultGroupName)
            throws IllegalAccessException, InstantiationException, NoSuchFieldException {
        ITree defaultGroup = (ITree) treeNodeClass.newInstance();
        ClassUtil.setFiledValue(defaultGroup, defaultGroup.getCodeFieldName(), defaultGroup.getDefaultGroupCode());
        ClassUtil.setFiledValue(defaultGroup, defaultGroup.getNameFieldName(), defaultGroup.getDefaultGroupName());
        ClassUtil.setFiledValue(defaultGroup, defaultGroup.getGroupTypeFieldName(), defaultGroup.getGroupTypeValue());
        if(StringUtils.isNotEmpty(defaultGroupCode)) {
            ClassUtil.setFiledValue(defaultGroup, defaultGroup.getCodeFieldName(), defaultGroupCode);
        }
        if(StringUtils.isNotEmpty(defaultGroupName)) {
            ClassUtil.setFiledValue(defaultGroup, defaultGroup.getCodeFieldName(), defaultGroupName);
        }
        return defaultGroup;
    }

}
